// PatternMiningReducer.java
package com.taxi.analysis.pattern;

import java.io.IOException;
import java.util.*;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

/**
 * 出行模式挖掘Reducer
 * 功能：基于去重数据进行模式挖掘和分析
 * 技术：去重技术 + 模式挖掘算法
 */
public class PatternMiningReducer extends Reducer<Text, Text, Text, Text> {

    @Override
    public void reduce(Text key, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        String keyStr = key.toString();

        if (keyStr.startsWith("EXACT_DEDUP_")) {
            processExactPatterns(keyStr, values, context);
        } else if (keyStr.startsWith("FUZZY_DEDUP_")) {
            processFuzzyPatterns(keyStr, values, context);
        } else if (keyStr.startsWith("TIME_WINDOW_")) {
            processTimeWindowPatterns(keyStr, values, context);
        } else if (keyStr.startsWith("USER_PATTERN_")) {
            processUserPatterns(keyStr, values, context);
        }
    }

    /**
     * 处理精确去重模式
     */
    private void processExactPatterns(String dedupKey, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        List<ExactPattern> patterns = new ArrayList<>();

        for (Text value : values) {
            try {
                String record = value.toString();
                if (record.startsWith("EXACT_PATTERN|")) {
                    String data = record.substring("EXACT_PATTERN|".length());
                    ExactPattern pattern = parseExactPattern(data);
                    if (pattern != null) {
                        patterns.add(pattern);
                    }
                }
            } catch (Exception e) {
                System.err.println("解析精确模式错误: " + value.toString());
            }
        }

        if (!patterns.isEmpty()) {
            // 精确模式分析
            ExactPatternAnalysis analysis = analyzeExactPatterns(patterns);

            // 输出精确模式分析结果
            outputExactPatternAnalysis(dedupKey, analysis, context);
        }
    }

    /**
     * 处理模糊去重模式
     */
    private void processFuzzyPatterns(String dedupKey, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        List<FuzzyPattern> patterns = new ArrayList<>();

        for (Text value : values) {
            try {
                String record = value.toString();
                if (record.startsWith("FUZZY_PATTERN|")) {
                    String data = record.substring("FUZZY_PATTERN|".length());
                    FuzzyPattern pattern = parseFuzzyPattern(data);
                    if (pattern != null) {
                        patterns.add(pattern);
                    }
                }
            } catch (Exception e) {
                System.err.println("解析模糊模式错误: " + value.toString());
            }
        }

        if (!patterns.isEmpty()) {
            // 模糊模式聚合分析
            FuzzyPatternAnalysis analysis = analyzeFuzzyPatterns(patterns);

            // 输出模糊模式分析结果
            outputFuzzyPatternAnalysis(dedupKey, analysis, context);
        }
    }

    /**
     * 处理时间窗口模式
     */
    private void processTimeWindowPatterns(String dedupKey, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        List<TimeWindowPattern> patterns = new ArrayList<>();

        for (Text value : values) {
            try {
                String record = value.toString();
                if (record.startsWith("TIME_WINDOW_PATTERN|")) {
                    String data = record.substring("TIME_WINDOW_PATTERN|".length());
                    TimeWindowPattern pattern = parseTimeWindowPattern(data);
                    if (pattern != null) {
                        patterns.add(pattern);
                    }
                }
            } catch (Exception e) {
                System.err.println("解析时间窗口模式错误: " + value.toString());
            }
        }

        if (!patterns.isEmpty()) {
            // 时间窗口模式分析
            TimeWindowAnalysis analysis = analyzeTimeWindowPatterns(patterns);

            // 输出时间窗口分析结果
            outputTimeWindowAnalysis(dedupKey, analysis, context);
        }
    }

    /**
     * 处理用户模式
     */
    private void processUserPatterns(String dedupKey, Iterable<Text> values, Context context)
            throws IOException, InterruptedException {

        List<UserPattern> patterns = new ArrayList<>();

        for (Text value : values) {
            try {
                String record = value.toString();
                if (record.startsWith("USER_PATTERN|")) {
                    String data = record.substring("USER_PATTERN|".length());
                    UserPattern pattern = parseUserPattern(data);
                    if (pattern != null) {
                        patterns.add(pattern);
                    }
                }
            } catch (Exception e) {
                System.err.println("解析用户模式错误: " + value.toString());
            }
        }

        if (!patterns.isEmpty()) {
            // 用户模式聚合分析
            UserPatternAnalysis analysis = analyzeUserPatterns(patterns);

            // 输出用户模式分析结果
            outputUserPatternAnalysis(dedupKey, analysis, context);
        }
    }

    /**
     * 分析精确模式
     */
    private ExactPatternAnalysis analyzeExactPatterns(List<ExactPattern> patterns) {
        ExactPatternAnalysis analysis = new ExactPatternAnalysis();

        Map<String, Integer> routePatternCounts = new HashMap<>();
        Map<String, Integer> timePatternCounts = new HashMap<>();
        Map<String, Integer> behaviorPatternCounts = new HashMap<>();
        Map<String, Integer> compositePatternCounts = new HashMap<>();
        Map<String, Integer> patternTypeCounts = new HashMap<>();

        double totalDistance = 0;
        double totalAmount = 0;
        double totalDuration = 0;
        double totalImportance = 0;

        for (ExactPattern pattern : patterns) {
            routePatternCounts.put(pattern.routePattern, routePatternCounts.getOrDefault(pattern.routePattern, 0) + 1);
            timePatternCounts.put(pattern.timePattern, timePatternCounts.getOrDefault(pattern.timePattern, 0) + 1);
            behaviorPatternCounts.put(pattern.behaviorPattern, behaviorPatternCounts.getOrDefault(pattern.behaviorPattern, 0) + 1);
            compositePatternCounts.put(pattern.compositePattern, compositePatternCounts.getOrDefault(pattern.compositePattern, 0) + 1);
            patternTypeCounts.put(pattern.patternType, patternTypeCounts.getOrDefault(pattern.patternType, 0) + 1);

            totalDistance += pattern.tripDistance;
            totalAmount += pattern.totalAmount;
            totalDuration += pattern.tripDuration;
            totalImportance += pattern.patternImportance;
        }

        analysis.totalPatterns = patterns.size();
        analysis.avgDistance = totalDistance / patterns.size();
        analysis.avgAmount = totalAmount / patterns.size();
        analysis.avgDuration = totalDuration / patterns.size();
        analysis.avgImportance = totalImportance / patterns.size();

        analysis.topRoutePattern = findMostFrequent(routePatternCounts);
        analysis.topTimePattern = findMostFrequent(timePatternCounts);
        analysis.topBehaviorPattern = findMostFrequent(behaviorPatternCounts);
        analysis.topCompositePattern = findMostFrequent(compositePatternCounts);
        analysis.topPatternType = findMostFrequent(patternTypeCounts);

        analysis.uniqueRoutePatterns = routePatternCounts.size();
        analysis.uniqueTimePatterns = timePatternCounts.size();
        analysis.uniqueBehaviorPatterns = behaviorPatternCounts.size();
        analysis.patternDiversity = calculatePatternDiversity(routePatternCounts, timePatternCounts, behaviorPatternCounts);

        return analysis;
    }

    /**
     * 分析模糊模式
     */
    private FuzzyPatternAnalysis analyzeFuzzyPatterns(List<FuzzyPattern> patterns) {
        FuzzyPatternAnalysis analysis = new FuzzyPatternAnalysis();

        Map<String, List<FuzzyPattern>> routeGroups = new HashMap<>();
        Map<String, List<FuzzyPattern>> timeGroups = new HashMap<>();

        double totalDistance = 0;
        double totalAmount = 0;
        double totalImportance = 0;
        int totalRouteFreq = 0;
        int totalTimeFreq = 0;

        for (FuzzyPattern pattern : patterns) {
            routeGroups.computeIfAbsent(pattern.routePattern, k -> new ArrayList<>()).add(pattern);
            timeGroups.computeIfAbsent(pattern.timePattern, k -> new ArrayList<>()).add(pattern);

            totalDistance += pattern.tripDistance;
            totalAmount += pattern.totalAmount;
            totalImportance += pattern.patternImportance;
            totalRouteFreq += pattern.routeFrequency;
            totalTimeFreq += pattern.timeFrequency;
        }

        analysis.totalPatterns = patterns.size();
        analysis.avgDistance = totalDistance / patterns.size();
        analysis.avgAmount = totalAmount / patterns.size();
        analysis.avgImportance = totalImportance / patterns.size();
        analysis.avgRouteFrequency = (double) totalRouteFreq / patterns.size();
        analysis.avgTimeFrequency = (double) totalTimeFreq / patterns.size();

        analysis.routeGroupCount = routeGroups.size();
        analysis.timeGroupCount = timeGroups.size();
        analysis.largestRouteGroup = findLargestGroup(routeGroups);
        analysis.largestTimeGroup = findLargestGroup(timeGroups);
        analysis.compressionRatio = calculateCompressionRatio(patterns.size(), routeGroups.size(), timeGroups.size());

        return analysis;
    }

    /**
     * 分析时间窗口模式
     */
    private TimeWindowAnalysis analyzeTimeWindowPatterns(List<TimeWindowPattern> patterns) {
        TimeWindowAnalysis analysis = new TimeWindowAnalysis();

        Map<String, Integer> routePatternCounts = new HashMap<>();
        Map<String, Integer> dateCounts = new HashMap<>();
        Map<Integer, Integer> hourCounts = new HashMap<>();

        double totalDistance = 0;
        double totalAmount = 0;
        double totalDuration = 0;
        double totalImportance = 0;
        int totalRouteFreq = 0;

        for (TimeWindowPattern pattern : patterns) {
            routePatternCounts.put(pattern.routePattern, routePatternCounts.getOrDefault(pattern.routePattern, 0) + 1);
            dateCounts.put(pattern.pickupDate, dateCounts.getOrDefault(pattern.pickupDate, 0) + 1);
            hourCounts.put(pattern.pickupHour, hourCounts.getOrDefault(pattern.pickupHour, 0) + 1);

            totalDistance += pattern.tripDistance;
            totalAmount += pattern.totalAmount;
            totalDuration += pattern.tripDuration;
            totalImportance += pattern.patternImportance;
            totalRouteFreq += pattern.routeFrequency;
        }

        analysis.totalPatterns = patterns.size();
        analysis.avgDistance = totalDistance / patterns.size();
        analysis.avgAmount = totalAmount / patterns.size();
        analysis.avgDuration = totalDuration / patterns.size();
        analysis.avgImportance = totalImportance / patterns.size();
        analysis.avgRouteFrequency = (double) totalRouteFreq / patterns.size();

        analysis.topRoutePattern = findMostFrequent(routePatternCounts);
        analysis.topDate = findMostFrequent(dateCounts);
        analysis.topHour = findMostFrequentHour(hourCounts);
        analysis.uniqueRoutes = routePatternCounts.size();
        analysis.uniqueDates = dateCounts.size();
        analysis.timeSpan = calculateTimeSpan(dateCounts.keySet());

        return analysis;
    }

    /**
     * 分析用户模式
     */
    private UserPatternAnalysis analyzeUserPatterns(List<UserPattern> patterns) {
        UserPatternAnalysis analysis = new UserPatternAnalysis();

        Map<String, Integer> routePatternCounts = new HashMap<>();
        Map<String, Integer> timePatternCounts = new HashMap<>();
        Map<String, Integer> behaviorPatternCounts = new HashMap<>();
        Map<String, Integer> patternTypeCounts = new HashMap<>();
        Map<String, Integer> locationCounts = new HashMap<>();

        double totalDistance = 0;
        double totalAmount = 0;
        double totalImportance = 0;

        for (UserPattern pattern : patterns) {
            routePatternCounts.put(pattern.routePattern, routePatternCounts.getOrDefault(pattern.routePattern, 0) + 1);
            timePatternCounts.put(pattern.timePattern, timePatternCounts.getOrDefault(pattern.timePattern, 0) + 1);
            behaviorPatternCounts.put(pattern.behaviorPattern, behaviorPatternCounts.getOrDefault(pattern.behaviorPattern, 0) + 1);
            patternTypeCounts.put(pattern.patternType, patternTypeCounts.getOrDefault(pattern.patternType, 0) + 1);
            locationCounts.put(pattern.pickupLocationId, locationCounts.getOrDefault(pattern.pickupLocationId, 0) + 1);

            totalDistance += pattern.tripDistance;
            totalAmount += pattern.totalAmount;
            totalImportance += pattern.patternImportance;
        }

        analysis.totalPatterns = patterns.size();
        analysis.avgDistance = totalDistance / patterns.size();
        analysis.avgAmount = totalAmount / patterns.size();
        analysis.avgImportance = totalImportance / patterns.size();

        analysis.topRoutePattern = findMostFrequent(routePatternCounts);
        analysis.topTimePattern = findMostFrequent(timePatternCounts);
        analysis.topBehaviorPattern = findMostFrequent(behaviorPatternCounts);
        analysis.topPatternType = findMostFrequent(patternTypeCounts);
        analysis.topLocation = findMostFrequent(locationCounts);

        analysis.routePatternDiversity = routePatternCounts.size();
        analysis.timePatternDiversity = timePatternCounts.size();
        analysis.behaviorPatternDiversity = behaviorPatternCounts.size();
        analysis.userLoyalty = calculateUserLoyalty(routePatternCounts, timePatternCounts);

        return analysis;
    }

    /**
     * 计算模式多样性
     */
    private double calculatePatternDiversity(Map<String, Integer> routePatterns,
                                             Map<String, Integer> timePatterns,
                                             Map<String, Integer> behaviorPatterns) {
        double routeEntropy = calculateEntropy(routePatterns);
        double timeEntropy = calculateEntropy(timePatterns);
        double behaviorEntropy = calculateEntropy(behaviorPatterns);

        return (routeEntropy + timeEntropy + behaviorEntropy) / 3.0;
    }

    /**
     * 计算信息熵
     */
    private double calculateEntropy(Map<String, Integer> counts) {
        int total = counts.values().stream().mapToInt(Integer::intValue).sum();
        double entropy = 0.0;

        for (int count : counts.values()) {
            if (count > 0) {
                double probability = (double) count / total;
                entropy -= probability * Math.log(probability) / Math.log(2);
            }
        }

        return entropy;
    }

    /**
     * 找到最大的组
     */
    private String findLargestGroup(Map<String, List<FuzzyPattern>> groups) {
        return groups.entrySet().stream()
                .max(Map.Entry.comparingByValue((a, b) -> Integer.compare(a.size(), b.size())))
                .map(entry -> entry.getKey() + "(" + entry.getValue().size() + "个)")
                .orElse("未知");
    }

    /**
     * 计算压缩比
     */
    private double calculateCompressionRatio(int originalSize, int routeGroups, int timeGroups) {
        int compressedSize = Math.max(routeGroups, timeGroups);
        return ((double) (originalSize - compressedSize) / originalSize) * 100;
    }

    /**
     * 计算时间跨度
     */
    private String calculateTimeSpan(Set<String> dates) {
        if (dates.size() <= 1) return "单日";

        List<String> sortedDates = new ArrayList<>(dates);
        Collections.sort(sortedDates);

        return sortedDates.get(0) + " 至 " + sortedDates.get(sortedDates.size() - 1) +
                " (共" + dates.size() + "天)";
    }

    /**
     * 计算用户忠诚度
     */
    private double calculateUserLoyalty(Map<String, Integer> routePatterns, Map<String, Integer> timePatterns) {
        // 基于模式重复度计算忠诚度
        int maxRouteCount = routePatterns.values().stream().mapToInt(Integer::intValue).max().orElse(0);
        int maxTimeCount = timePatterns.values().stream().mapToInt(Integer::intValue).max().orElse(0);
        int totalPatterns = routePatterns.values().stream().mapToInt(Integer::intValue).sum();

        return ((double) (maxRouteCount + maxTimeCount) / (totalPatterns * 2)) * 100;
    }

    /**
     * 找出最频繁的小时
     */
    private String findMostFrequentHour(Map<Integer, Integer> hourCounts) {
        return hourCounts.entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(entry -> entry.getKey() + "时(" + entry.getValue() + "次)")
                .orElse("未知");
    }

    /**
     * 输出精确模式分析结果
     */
    private void outputExactPatternAnalysis(String dedupKey, ExactPatternAnalysis analysis, Context context)
            throws IOException, InterruptedException {

        String analysisInfo = String.format("精确模式|总模式:%d|平均距离:%.2f|平均费用:%.2f|平均时长:%.2f|平均重要性:%.3f|热门路线:%s|热门时间:%s|热门行为:%s|热门复合:%s|主要类型:%s|路线多样性:%d|时间多样性:%d|行为多样性:%d|模式多样性:%.3f",
                analysis.totalPatterns, analysis.avgDistance, analysis.avgAmount,
                analysis.avgDuration, analysis.avgImportance, analysis.topRoutePattern,
                analysis.topTimePattern, analysis.topBehaviorPattern, analysis.topCompositePattern,
                analysis.topPatternType, analysis.uniqueRoutePatterns, analysis.uniqueTimePatterns,
                analysis.uniqueBehaviorPatterns, analysis.patternDiversity);

        context.write(new Text("精确模式_" + dedupKey), new Text(analysisInfo));
    }

    /**
     * 输出模糊模式分析结果
     */
    private void outputFuzzyPatternAnalysis(String dedupKey, FuzzyPatternAnalysis analysis, Context context)
            throws IOException, InterruptedException {

        String analysisInfo = String.format("模糊模式|总模式:%d|平均距离:%.2f|平均费用:%.2f|平均重要性:%.3f|平均路线频率:%.1f|平均时间频率:%.1f|路线组数:%d|时间组数:%d|最大路线组:%s|最大时间组:%s|压缩比:%.2f%%",
                analysis.totalPatterns, analysis.avgDistance, analysis.avgAmount,
                analysis.avgImportance, analysis.avgRouteFrequency, analysis.avgTimeFrequency,
                analysis.routeGroupCount, analysis.timeGroupCount, analysis.largestRouteGroup,
                analysis.largestTimeGroup, analysis.compressionRatio);

        context.write(new Text("模糊模式_" + dedupKey), new Text(analysisInfo));
    }

    /**
     * 输出时间窗口分析结果
     */
    private void outputTimeWindowAnalysis(String dedupKey, TimeWindowAnalysis analysis, Context context)
            throws IOException, InterruptedException {

        String analysisInfo = String.format("时间窗口|总模式:%d|平均距离:%.2f|平均费用:%.2f|平均时长:%.2f|平均重要性:%.3f|平均路线频率:%.1f|热门路线:%s|热门日期:%s|热门小时:%s|唯一路线:%d|唯一日期:%d|时间跨度:%s",
                analysis.totalPatterns, analysis.avgDistance, analysis.avgAmount,
                analysis.avgDuration, analysis.avgImportance, analysis.avgRouteFrequency,
                analysis.topRoutePattern, analysis.topDate, analysis.topHour,
                analysis.uniqueRoutes, analysis.uniqueDates, analysis.timeSpan);

        context.write(new Text("时间窗口_" + dedupKey), new Text(analysisInfo));
    }

    /**
     * 输出用户模式分析结果
     */
    private void outputUserPatternAnalysis(String dedupKey, UserPatternAnalysis analysis, Context context)
            throws IOException, InterruptedException {

        String analysisInfo = String.format("用户模式|总模式:%d|平均距离:%.2f|平均费用:%.2f|平均重要性:%.3f|热门路线:%s|热门时间:%s|热门行为:%s|主要类型:%s|热门地点:%s|路线多样性:%d|时间多样性:%d|行为多样性:%d|用户忠诚度:%.2f%%",
                analysis.totalPatterns, analysis.avgDistance, analysis.avgAmount,
                analysis.avgImportance, analysis.topRoutePattern, analysis.topTimePattern,
                analysis.topBehaviorPattern, analysis.topPatternType, analysis.topLocation,
                analysis.routePatternDiversity, analysis.timePatternDiversity,
                analysis.behaviorPatternDiversity, analysis.userLoyalty);

        context.write(new Text("用户模式_" + dedupKey), new Text(analysisInfo));
    }

    /**
     * 找出最频繁的项目
     */
    private String findMostFrequent(Map<String, Integer> counts) {
        return counts.entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(entry -> entry.getKey() + "(" + entry.getValue() + "次)")
                .orElse("未知");
    }

    // 解析方法
    private ExactPattern parseExactPattern(String data) {
        try {
            String[] fields = data.split("\\|");
            if (fields.length >= 12) {
                ExactPattern pattern = new ExactPattern();
                pattern.pickupLocationId = fields[0];
                pattern.dropoffLocationId = fields[1];
                pattern.pickupDatetime = fields[2];
                pattern.routePattern = fields[3];
                pattern.timePattern = fields[4];
                pattern.behaviorPattern = fields[5];
                pattern.compositePattern = fields[6];
                pattern.tripDistance = Double.parseDouble(fields[7]);
                pattern.totalAmount = Double.parseDouble(fields[8]);
                pattern.tripDuration = Double.parseDouble(fields[9]);
                pattern.patternImportance = Double.parseDouble(fields[10]);
                pattern.patternType = fields[11];
                return pattern;
            }
        } catch (Exception e) {
            System.err.println("解析精确模式错误: " + data);
        }
        return null;
    }

    private FuzzyPattern parseFuzzyPattern(String data) {
        try {
            String[] fields = data.split("\\|");
            if (fields.length >= 11) {
                FuzzyPattern pattern = new FuzzyPattern();
                pattern.pickupLocationId = fields[0];
                pattern.dropoffLocationId = fields[1];
                pattern.pickupHour = Integer.parseInt(fields[2]);
                pattern.pickupWeekday = Integer.parseInt(fields[3]);
                pattern.routePattern = fields[4];
                pattern.timePattern = fields[5];
                pattern.tripDistance = Double.parseDouble(fields[6]);
                pattern.totalAmount = Double.parseDouble(fields[7]);
                pattern.routeFrequency = Integer.parseInt(fields[8]);
                pattern.timeFrequency = Integer.parseInt(fields[9]);
                pattern.patternImportance = Double.parseDouble(fields[10]);
                return pattern;
            }
        } catch (Exception e) {
            System.err.println("解析模糊模式错误: " + data);
        }
        return null;
    }

    private TimeWindowPattern parseTimeWindowPattern(String data) {
        try {
            String[] fields = data.split("\\|");
            if (fields.length >= 8) {
                TimeWindowPattern pattern = new TimeWindowPattern();
                pattern.routePattern = fields[0];
                pattern.pickupDate = fields[1];
                pattern.pickupHour = Integer.parseInt(fields[2]);
                pattern.tripDistance = Double.parseDouble(fields[3]);
                pattern.totalAmount = Double.parseDouble(fields[4]);
                pattern.tripDuration = Double.parseDouble(fields[5]);
                pattern.routeFrequency = Integer.parseInt(fields[6]);
                pattern.patternImportance = Double.parseDouble(fields[7]);
                return pattern;
            }
        } catch (Exception e) {
            System.err.println("解析时间窗口模式错误: " + data);
        }
        return null;
    }

    private UserPattern parseUserPattern(String data) {
        try {
            String[] fields = data.split("\\|");
            if (fields.length >= 8) {
                UserPattern pattern = new UserPattern();
                pattern.routePattern = fields[0];
                pattern.timePattern = fields[1];
                pattern.behaviorPattern = fields[2];
                pattern.pickupLocationId = fields[3];
                pattern.tripDistance = Double.parseDouble(fields[4]);
                pattern.totalAmount = Double.parseDouble(fields[5]);
                pattern.patternImportance = Double.parseDouble(fields[6]);
                pattern.patternType = fields[7];
                return pattern;
            }
        } catch (Exception e) {
            System.err.println("解析用户模式错误: " + data);
        }
        return null;
    }

    // 内部类定义
    private static class ExactPattern {
        String pickupLocationId, dropoffLocationId, pickupDatetime;
        String routePattern, timePattern, behaviorPattern, compositePattern, patternType;
        double tripDistance, totalAmount, tripDuration, patternImportance;
    }

    private static class FuzzyPattern {
        String pickupLocationId, dropoffLocationId, routePattern, timePattern;
        int pickupHour, pickupWeekday, routeFrequency, timeFrequency;
        double tripDistance, totalAmount, patternImportance;
    }

    private static class TimeWindowPattern {
        String routePattern, pickupDate;
        int pickupHour, routeFrequency;
        double tripDistance, totalAmount, tripDuration, patternImportance;
    }

    private static class UserPattern {
        String routePattern, timePattern, behaviorPattern, pickupLocationId, patternType;
        double tripDistance, totalAmount, patternImportance;
    }

    private static class ExactPatternAnalysis {
        int totalPatterns, uniqueRoutePatterns, uniqueTimePatterns, uniqueBehaviorPatterns;
        double avgDistance, avgAmount, avgDuration, avgImportance, patternDiversity;
        String topRoutePattern, topTimePattern, topBehaviorPattern, topCompositePattern, topPatternType;
    }

    private static class FuzzyPatternAnalysis {
        int totalPatterns, routeGroupCount, timeGroupCount;
        double avgDistance, avgAmount, avgImportance, avgRouteFrequency, avgTimeFrequency, compressionRatio;
        String largestRouteGroup, largestTimeGroup;
    }

    private static class TimeWindowAnalysis {
        int totalPatterns, uniqueRoutes, uniqueDates;
        double avgDistance, avgAmount, avgDuration, avgImportance, avgRouteFrequency;
        String topRoutePattern, topDate, topHour, timeSpan;
    }

    private static class UserPatternAnalysis {
        int totalPatterns, routePatternDiversity, timePatternDiversity, behaviorPatternDiversity;
        double avgDistance, avgAmount, avgImportance, userLoyalty;
        String topRoutePattern, topTimePattern, topBehaviorPattern, topPatternType, topLocation;
    }
}
